package com.itheima.appserver.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.appserver.interceptor.UserThreadLocal;
import com.itheima.commons.constants.Constants;
import com.itheima.commons.enums.CommentType;
import com.itheima.commons.model.domain.UserInfo;
import com.itheima.commons.model.mongo.Comment;
import com.itheima.commons.model.mongo.Publish;
import com.itheima.commons.model.mongo.Video;
import com.itheima.commons.model.vo.CommentVo;
import com.itheima.commons.model.vo.PageResult;
import com.itheima.dubbo.interfaces.CommentApi;
import com.itheima.dubbo.interfaces.PublishApi;
import com.itheima.dubbo.interfaces.VideoApi;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 评论业务类
 */
@Service
public class CommentsService {

    @Reference
    private CommentApi commentApi;

    @Reference
    private PublishApi publishApi;

    @Reference
    private VideoApi videoApi;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private PublishMQService mqService;

    /**
     * 对圈子进行点赞
     */
    public Long publishLike(String publishId) {
        Long likeCount = this.saveComment(publishId, null, CommentType.LIKE, "publish");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY, likeCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId(), "1");
        // 给MQ发送消息
        mqService.likePublishMsg(publishId);
        return likeCount;
    }

    /**
     * 对小视频进行点赞
     */
    public Long videoLike(String videoId) {
        Long likeCount = this.saveComment(videoId, null, CommentType.LIKE, "video");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_LIKE_HASHKEY, likeCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().put(Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_ISLIKE_HASHKEY + UserThreadLocal.getUserId(), "1");
        return likeCount;
    }

    /**
     * 对评论进行点赞
     */
    public Long commentLike(String commentId) {
        Long likeCount = this.saveComment(commentId, null, CommentType.LIKE, "comment");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_LIKE_HASHKEY, likeCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().put(Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId(), "1");
        return likeCount;
    }

    // 对圈子进行喜欢
    public Long publishLove(String publishId) {
        Long loveCount = this.saveComment(publishId, null, CommentType.LOVE, "publish");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LOVE_HASHKEY, loveCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLOVE_HASHKEY + UserThreadLocal.getUserId(), "1");
        return loveCount;
    }

    /**
     * 对圈子进行评论
     */
    public Long publishComment(String publishId, String content) {
        Long commentCount = this.saveComment(publishId, content, CommentType.COMMENT, "publish");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY, commentCount.toString());
        return commentCount;
    }

    /**
     * 对小视频进行评论
     */
    public Long videoComment(String videoId, String content) {
        Long commentCount = this.saveComment(videoId, content, CommentType.COMMENT, "video");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_COMMENT_HASHKEY, commentCount.toString());
        return commentCount;
    }

    /**
     * 对圈子进行评论
     */
    public Long commentComment(String commentId, String content) {
        Long commentCount = this.saveComment(commentId, content, CommentType.COMMENT, "comment");
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_LIKE_HASHKEY, commentCount.toString());
        return commentCount;
    }


    /**
     * 对圈子取消点赞
     */
    public Long cancelPublishLike(String publishId) {
        Long delCount = commentApi.delComment(UserThreadLocal.getUserId(), publishId, CommentType.LIKE.getType());
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY, delCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().delete(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
        return delCount;
    }

    /**
     * 对小视频取消点赞
     */
    public Long cancelVideoLike(String videoId) {
        Long delCount = commentApi.delComment(UserThreadLocal.getUserId(), videoId, CommentType.LIKE.getType());
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_LIKE_HASHKEY, delCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().delete(Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
        return delCount;
    }

    /**
     * 对评论取消点赞
     */
    public Long cancelCommentLike(String commentId) {
        Long delCount = commentApi.delComment(UserThreadLocal.getUserId(), commentId, CommentType.LIKE.getType());
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_LIKE_HASHKEY, delCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().delete(Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
        return delCount;
    }

    /**
     * 对圈子取消喜欢
     */
    public Long cancelPublishLove(String publishId) {
        Long delCount = commentApi.delComment(UserThreadLocal.getUserId(), publishId, CommentType.LOVE.getType());
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LOVE_HASHKEY, delCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().delete(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLOVE_HASHKEY + UserThreadLocal.getUserId());
        return delCount;
    }

    /**
     * 查询评论列表
     *
     * @param publishId
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult queryCommentList(String publishId, Integer page, Integer pageSize) {
        PageResult pageResult = commentApi.queryCommentList(publishId, page, pageSize);
        if (CollUtil.isEmpty(pageResult.getItems())) {
            return pageResult;
        }
        // 从评论列表中提取发布评论人的ID
        List<Long> userIds = CollUtil.getFieldValues(pageResult.getItems(), "userId", Long.class);

        // 根据这个发布人的id集合去查询tb_user_info
        Map<Long, UserInfo> userInfoList = userInfoService.findUserInfoListByUserIds(null, userIds);

        List<CommentVo> voList = new ArrayList<>();
        for (Object item : pageResult.getItems()) {
            Comment comment = (Comment) item;
            // 拼凑vo对象
            CommentVo commentVo = new CommentVo();
            // 评论的id
            commentVo.setId(comment.getId().toHexString());
            // 评论的内容
            commentVo.setContent(comment.getContent());
            // 评论的时间
            commentVo.setCreateDate(DateUtil.date(comment.getCreated()).toString("HH:mm"));

            // 根据评论发布人的id找到发布人的详情
            UserInfo userInfo = userInfoList.get(comment.getUserId());
            // 发布评论人的头像
            commentVo.setAvatar(userInfo.getLogo());
            // 发布评论人的昵称
            commentVo.setNickname(userInfo.getNickName());

            // 评论的点赞数量
            commentVo.setLikeCount(this.queryCommentLikeCount(comment.getId().toHexString()).intValue());
            // 当前登录用户是否对该评论点赞
            commentVo.setHasLiked(this.queryUser2CommentIsLike(comment.getId().toHexString()) ? 1 : 0);
            voList.add(commentVo);
        }
        pageResult.setItems(voList);
        return pageResult;
    }

    /**
     * 根据圈子id查询点赞数量
     *
     * @param publishId
     * @return
     */
    public Long queryPublishLikeCount(String publishId) {
        return queryLikeCount(publishId, Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY);
    }

    /**
     * 根据小视频id查询点赞数量
     *
     * @param videoId
     * @return
     */
    public Long queryVideoLikeCount(String videoId) {
        return queryLikeCount(videoId, Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_LIKE_HASHKEY);
    }

    /**
     * 根据评论id查询点赞数量
     *
     * @param commentId
     * @return
     */
    public Long queryCommentLikeCount(String commentId) {
        return queryLikeCount(commentId, Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_LIKE_HASHKEY);
    }

    /**
     * 根据圈子id查询评论数量
     *
     * @param publishId
     * @return
     */
    public Long queryPublishCommentCount(String publishId) {
        return this.queryCommentCount(publishId, Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_COMMENT_HASHKEY);
    }

    /**
     * 根据小视频id查询评论数量
     *
     * @param videoId
     * @return
     */
    public Long queryVideoCommentCount(String videoId) {
        return this.queryCommentCount(videoId, Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_COMMENT_HASHKEY);
    }

    /**
     * 当前用户对某个圈子是否点赞
     *
     * @param publishId
     * @return
     */
    public Boolean queryUser2PublishIsLike(String publishId) {
        return this.queryUserIsLike(publishId, Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
    }

    /**
     * 当前用户对某个小视频是否点赞
     *
     * @param videoId
     * @return
     */
    public Boolean queryUser2VideoIsLike(String videoId) {
        return this.queryUserIsLike(videoId, Constants.VIDEOS_INTERACT_KEY + videoId, Constants.VIDEO_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
    }

    /**
     * 当前用户对某个评论是否点赞
     *
     * @param commentId
     * @return
     */
    public Boolean queryUser2CommentIsLike(String commentId) {
        return this.queryUserIsLike(commentId, Constants.COMMENT_INTERACT_KEY + commentId, Constants.COMMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
    }

    /**
     * 根据圈子id查询喜欢数量
     *
     * @param publishId
     * @return
     */
    public Long queryLoveCount(String publishId) {
        Long loveCount = Convert.toLong(redisTemplate.opsForHash().get(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LOVE_HASHKEY));
        if (ObjectUtil.isNull(loveCount)) {
            // 从MongoDB中进行查询
            loveCount = commentApi.queryCommentCount(publishId, CommentType.LOVE.getType());
            // 把查询到数据给保存到Redis中
            redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LOVE_HASHKEY, loveCount.toString());
        }
        return loveCount;
    }

    /**
     * 某用户是否对某条圈子点击了喜欢
     *
     * @param publishId
     * @return
     */
    public Boolean queryUserIsLove(String publishId) {
        Boolean isLove = redisTemplate.opsForHash().hasKey(Constants.MOVEMENTS_INTERACT_KEY + publishId,
                Constants.MOVEMENT_ISLOVE_HASHKEY + UserThreadLocal.getUserId());
        if (!isLove) {
            // 从MongoDB中进行查询
            isLove = commentApi.queryUserIsLikeORIsLove(UserThreadLocal.getUserId(), publishId, CommentType.LOVE.getType());
            if (isLove) {
                // 把查询到数据给保存到Redis中
                redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLOVE_HASHKEY + UserThreadLocal.getUserId(), "1");
            }
        }
        return isLove;
    }

    /**
     * 点赞/喜欢/评论通用方法封装
     *
     * @param publishId      评论对象的ID
     * @param commentContent 文本评论的内容
     * @param type           点赞/喜欢/文本评论
     * @param targetType     圈子/评论/小视频
     * @return
     */
    private Long saveComment(String publishId, String commentContent, CommentType type, String targetType) {

        Comment comment = new Comment();
        // 评论ID
        comment.setId(new ObjectId());
        // 圈子ID/评论ID
        comment.setPublishId(new ObjectId(publishId));
        // 评论类型
        comment.setCommentType(type.getType());
        // 评论的文本
        comment.setContent(commentContent);
        // 评论人的ID
        comment.setUserId(UserThreadLocal.getUserId());
        // 评论树 该功能不实现
        comment.setIsParent(false);
        comment.setParentId(null);
        comment.setCreated(System.currentTimeMillis());

        // 发布圈子/评论/小视频的人的ID
        switch (targetType) {
            case "publish": {
                Publish publish = publishApi.queryPublishById(publishId);
                comment.setPublishUserId(publish.getUserId());
                break;
            }
            case "video": {
                Video video = videoApi.queryVideoById(publishId);
                comment.setPublishUserId(video.getUserId());
                break;
            }
            case "comment": {
                Comment commentId = commentApi.queryCommentById(publishId);
                comment.setPublishUserId(commentId.getUserId());
                break;
            }
        }

        return commentApi.saveComment(comment);
    }

    private Long queryCommentCount(String publishId, String redisKey, String hashKey) {
        Long commentCount = Convert.toLong(redisTemplate.opsForHash().get(redisKey, hashKey));
        if (ObjectUtil.isNull(commentCount)) {
            // 从MongoDB中进行查询
            commentCount = commentApi.queryCommentCount(publishId, CommentType.COMMENT.getType());
            // 把查询到数据给保存到Redis中
            redisTemplate.opsForHash().put(redisKey, hashKey, commentCount.toString());
        }
        return commentCount;
    }

    private Long queryLikeCount(String publishId, String redisKey, String hashKey) {
        Long likeCount = Convert.toLong(redisTemplate.opsForHash().get(redisKey, hashKey));
        if (ObjectUtil.isNull(likeCount)) {
            // 从MongoDB中进行查询
            likeCount = commentApi.queryCommentCount(publishId, CommentType.LIKE.getType());
            // 把查询到数据给保存到Redis中
            redisTemplate.opsForHash().put(redisKey, hashKey, likeCount.toString());
        }
        return likeCount;
    }

    private Boolean queryUserIsLike(String publishId, String redisKey, String hashKey) {
        Boolean isLike = redisTemplate.opsForHash().hasKey(redisKey, hashKey);
        if (!isLike) {
            // 从MongoDB中进行查询
            isLike = commentApi.queryUserIsLikeORIsLove(UserThreadLocal.getUserId(), publishId, CommentType.LIKE.getType());
            if (isLike) {
                // 把查询到数据给保存到Redis中
                redisTemplate.opsForHash().put(redisKey, hashKey, "1");
            }
        }
        return isLike;
    }
}
